package com.crm.crm.aspect;

import com.crm.crm.annotation.Log;
import com.crm.crm.domain.ControllerLog;
import com.crm.crm.domain.ControllerLog;
import com.crm.crm.repository.ControllerLogRepository;
import com.crm.crm.util.IpUtils;
import com.crm.crm.util.UserThreadLocalUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Aspect
@Component
public class ControllerLogAspect {

    @Autowired
    private ControllerLogRepository logRepository;

    @Autowired
    private ObjectMapper objectMapper;

    //    @Around("execution(* com.crm.crm.controller..*.*(..))")
    @Around("execution(* com.crm.crm.controller..*.*(..)) " +
            "&& !within(com.crm.crm.controller.LoginController) " +
            "&& !execution(* com.crm.crm.controller.UserController.exportExcel(..))" +
            "&& !within(com.crm.crm.controller.LogController) " +
            "&& !within(com.crm.crm.controller.SystemController) ")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取请求属性
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 创建日志对象
        ControllerLog controllerLog = new ControllerLog();
        controllerLog.setOperationTime(LocalDateTime.now());

        // 设置请求信息
        controllerLog.setRequestUrl(request.getRequestURI());
        controllerLog.setRequestMethod(request.getMethod());

        // 设置用户信息
//        String username = Optional.ofNullable(request.getAttribute("username"))
//                .map(Object::toString)
//                .orElse("anonymous");
        String username = UserThreadLocalUtil.getCurrentUserName();
        String ip = IpUtils.getIpAddr(request);
        String region = IpUtils.getRegion(ip); // 需要实现IP地区查询
        controllerLog.setUserInfo(String.format("%s / %s / %s", username, ip, region));

        // 设置方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        controllerLog.setClassMethod(joinPoint.getTarget().getClass().getName() + "." + method.getName() + "()");

        // 获取操作模块(从注解中读取)
        Optional.ofNullable(method.getAnnotation(Log.class))
                .ifPresent(log -> controllerLog.setModule(log.value()));

        // 获取请求参数
        controllerLog.setRequestParams(getRequestParams(joinPoint, request));

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        try {
            // 执行方法
            Object result = joinPoint.proceed();
            stopWatch.stop();

            // 设置响应信息
            controllerLog.setResponseData(objectMapper.writeValueAsString(result));
            controllerLog.setStatus("正常");
            controllerLog.setExecutionTime(stopWatch.getTotalTimeMillis());

            logRepository.save(controllerLog);
            return result;

        } catch (Exception ex) {
            stopWatch.stop();

            // 设置异常信息
            controllerLog.setStatus("异常");
            controllerLog.setResponseData(ex.getClass().getSimpleName() + ": " + ex.getMessage());
            controllerLog.setExecutionTime(stopWatch.getTotalTimeMillis());

            logRepository.save(controllerLog);
            throw ex;
        }
    }

    /**
     * 获取请求参数
     */
    private String getRequestParams(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        String params = "";
        try {
            // 获取参数名和值
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            String[] paramNames = signature.getParameterNames();
            Object[] paramValues = joinPoint.getArgs();

            // 如果是GET请求，优先从请求参数获取
            if ("GET".equalsIgnoreCase(request.getMethod())) {
                params = request.getQueryString();
            }

            // 如果不是GET请求或者没有查询参数，则从方法参数获取
            if (params == null || params.isEmpty()) {
                Map<String, Object> paramMap = new HashMap<>();
                for (int i = 0; i < paramNames.length; i++) {
                    // 过滤HttpServletRequest/HttpServletResponse等特殊参数
                    if (!(paramValues[i] instanceof HttpServletRequest) &&
                            !(paramValues[i] instanceof HttpServletResponse)) {
                        paramMap.put(paramNames[i], paramValues[i]);
                    }
                }
                params = objectMapper.writeValueAsString(paramMap);
            }
        } catch (Exception e) {
            params = "参数获取失败";
        }
        return params;
    }
}